#include "Vector3.h"
#include <math.h>
#include <iostream>
#include <ctime>
#include <cstdlib>

using namespace std;

Vector3::Vector3 (float new_x, float new_y, float new_z) {
	setVector(new_x, new_y, new_z);
}

Vector3::Vector3() {
	setVector(0, 0, 0);
}

Vector3::Vector3(const Vector3& newVector) {
	setVector(newVector.x, newVector.y, newVector.z);
}
void Vector3::setVector (float new_x, float new_y, float new_z) {
	x = new_x;
	y = new_y;
	z = new_z;
}

float Vector3::dot(Vector3 A, Vector3 B) {
	return A.x*B.x +  A.y*B.y +  A.z*B.z;
}

Vector3 Vector3::reflect(Vector3 invec, Vector3 normal)
{
    return Vector3::normalize(invec - (2 * Vector3::dot(invec, normal)) * normal);
}

Vector3 Vector3::cross(Vector3 A, Vector3 B) {

	return Vector3(A.y * B.z - B.y * A.z, B.x * A.z - A.x * B.z, A.x * B.y - B.x * A.y);
}

float Vector3::length() {
	return sqrt(x * x + y * y + z * z);
}

float Vector3::LengthPow2()
{
    return x*x + y*y + z*z;
}

Vector3 Vector3::normalize(Vector3 A) {
	return Vector3(A / A.length());
}


Vector3 Vector3::Mix(Vector3 A, Vector3 B, float var) {
    return (1.0 - var) * A + var * B;
}

Vector3 Vector3::operator/(float A) {
	return Vector3(x/A, y/A, z/A);
}

Vector3 Vector3::operator-(Vector3 A) {
	return Vector3(x - A.x, y - A.y, z - A.z);
}

Vector3 Vector3::operator+(Vector3 A) {
	return Vector3(A.x + x, A.y + y, A.z + z);
}

Vector3 operator*(float A, Vector3 B) {
	return Vector3(B.x*A, B.y*A, B.z*A);
}

Vector3 operator*(Vector3 B, float A) {
	return Vector3(B.x*A, B.y*A, B.z*A);
}

Vector3 Vector3::operator*(Vector3 A) {
	return Vector3(A.x * x, A.y * y, A.z * z);
}


float Vector3::operator[](int at)
{
    if ( at == 0)
        return x;
    if ( at == 1)
        return y;
    if ( at == 2)
        return z;
}

void Vector3::operator=(Vector3 A) {
	x = A.x;
    y = A.y;
    z = A.z;
}

Vector3 Vector3::GetRandomNormalizedKernel()
{
    float random_x = rand();
    random_x /= RAND_MAX ;
    float random_y = rand();
    random_y /= RAND_MAX ;
    float random_z = rand();
    random_z /= RAND_MAX ;
    Vector3 kernel = Vector3::normalize(Vector3(2.0*random_x-1, 2.0 * random_y - 1.0, 2.0 * random_z - 1.0));
    return kernel;
}

std::ostream& operator<< (std::ostream& out, const Vector3 A) {
	cout << "Vector3: (" << A.x << ", " << A.y << ", " << A.z << ")";
	return out;
}
